/**
 * @file http_client.c
 * @brief 基于libcurl的HTTP客户端实现
 */

 #include "http_client.h"
 #include <curl/curl.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
 
 //-----------------------------------------------------------------------------
 // 全局状态定义（仅在此文件内可见）
 //-----------------------------------------------------------------------------
 
 static CURL* g_curl_handle = NULL;            ///< CURL全局句柄（单例模式）
 static struct curl_slist* g_header_list = NULL; ///< 持久化请求头链表
 static char* g_ca_cert_path = NULL;            ///< CA证书路径（动态分配内存）
 static unsigned int g_timeout_sec = 30;        ///< 全局超时时间（秒）
 static bool g_curl_global_initialized = false; ///< 标记CURL全局环境初始化状态
 
 //-----------------------------------------------------------------------------
 // 内部工具函数声明
 //-----------------------------------------------------------------------------
 
 static void log_curl_error(CURLcode code, const char* context);
 
 //-----------------------------------------------------------------------------
 // 公开接口实现
 //-----------------------------------------------------------------------------
 
 /**
  * @brief 初始化HTTP客户端全局环境
  * @param ca_cert_path CA证书路径（NULL表示禁用证书验证）
  * @return bool 初始化是否成功
  * 
  * 核心功能：
  * 1. 单次初始化libcurl全局环境
  * 2. 创建持久化CURL easy句柄
  * 3. 配置SSL/TLS安全策略
  * 4. 设置基础网络参数
  * 
  * 安全模式：
  * - 传入证书路径：启用严格证书校验
  * - 传入NULL：调试模式（不推荐生产环境）
  */
 bool HTTP_ClientInit(const char* ca_cert_path) {
     //---------------------------------------
     // 初始化CURL全局环境（仅一次）
     //---------------------------------------
     if (!g_curl_global_initialized) {
         CURLcode code = curl_global_init(CURL_GLOBAL_DEFAULT);
         if (code != CURLE_OK) {
             log_curl_error(code, "curl_global_init");
             return false;  // 全局环境初始化失败
         }
         g_curl_global_initialized = true;
     }
 
     //---------------------------------------
     // 创建CURL easy句柄（单例模式）
     //---------------------------------------
     if (g_curl_handle) return true; // 避免重复初始化
 
     g_curl_handle = curl_easy_init();
     if (!g_curl_handle) {
         fprintf(stderr, "[HTTP] 无法创建CURL句柄\n");
         return false;  // 核心资源分配失败
     }
 
     //---------------------------------------
     // SSL/TLS安全配置
     //---------------------------------------
     if (ca_cert_path) {
         // 持久化证书路径（需要释放内存）
         g_ca_cert_path = strdup(ca_cert_path);  // 深拷贝证书路径
         if (!g_ca_cert_path) {
             fprintf(stderr, "[HTTP] 内存分配失败\n");
             curl_easy_cleanup(g_curl_handle);
             g_curl_handle = NULL;
             return false;  // 内存不足
         }
 
         // 严格证书校验配置
         curl_easy_setopt(g_curl_handle, CURLOPT_CAINFO, g_ca_cert_path);  // 指定CA证书
         curl_easy_setopt(g_curl_handle, CURLOPT_SSL_VERIFYPEER, 1L);      // 验证对端证书
         curl_easy_setopt(g_curl_handle, CURLOPT_SSL_VERIFYHOST, 2L);      // 严格主机名验证
     } else {
         // 调试模式安全警告
         fprintf(stderr, "[WARN] SSL证书验证已禁用\n");
         curl_easy_setopt(g_curl_handle, CURLOPT_SSL_VERIFYPEER, 0L);  // 关闭证书验证
     }
 
     //---------------------------------------
     // 通用网络配置
     //---------------------------------------
     curl_easy_setopt(g_curl_handle, CURLOPT_USERAGENT, "DeepSeekClient/1.0");  // 客户端标识
     curl_easy_setopt(g_curl_handle, CURLOPT_FOLLOWLOCATION, 1L);     // 启用自动重定向
     curl_easy_setopt(g_curl_handle, CURLOPT_MAXREDIRS, 3L);          // 最多3次重定向
     curl_easy_setopt(g_curl_handle, CURLOPT_TIMEOUT, g_timeout_sec); // 总请求超时时间
 
     return true;
 }
 
 /**
  * @brief 发送HTTP请求并处理响应
  * @param config 请求配置参数
  * @param callback 响应数据回调函数
  * @param userdata 用户上下文指针
  * @return HTTP_Status 请求最终状态
  * 
  * 核心流程：
  * 1. 请求参数校验
  * 2. CURL会话重置
  * 3. HTTP方法配置
  * 4. 请求头构建与管理
  * 5. 请求执行与错误处理
  */
 HTTP_Status HTTP_SendRequest(const HTTP_RequestConfig* config,
                             HTTP_ResponseCallback callback,
                             void* userdata) {
     // 校验全局句柄和必要参数（防御性编程）
     if (!g_curl_handle || !config || !config->url) {
         return HTTP_ERR_INIT;  // 初始化未完成或参数错误
     }
 
     // 重置CURL会话（清除上次请求的配置）
     curl_easy_reset(g_curl_handle);
 
     // 配置HTTP方法及请求体（支持RESTful方法）
     switch (config->method) {
         case HTTP_GET:
             curl_easy_setopt(g_curl_handle, CURLOPT_HTTPGET, 1L);  // 标准GET方法
             break;
         case HTTP_POST: {
             // POST方法需要设置请求体
             curl_easy_setopt(g_curl_handle, CURLOPT_POST, 1L);
             if (config->request_body) {
                 // 精确设置请求体大小（避免依赖null终止符）
                 curl_easy_setopt(g_curl_handle, CURLOPT_POSTFIELDS, config->request_body);
                 curl_easy_setopt(g_curl_handle, CURLOPT_POSTFIELDSIZE, config->body_size);
             }
             break;
         }
         case HTTP_PUT: {
             // PUT方法需要自定义请求方法
             curl_easy_setopt(g_curl_handle, CURLOPT_CUSTOMREQUEST, "PUT");
             if (config->request_body) {
                 curl_easy_setopt(g_curl_handle, CURLOPT_POSTFIELDS, config->request_body);
                 curl_easy_setopt(g_curl_handle, CURLOPT_POSTFIELDSIZE, config->body_size);
             }
             break;
         }
         case HTTP_DELETE:
             curl_easy_setopt(g_curl_handle, CURLOPT_CUSTOMREQUEST, "DELETE"); // 删除资源
             break;
         default:
             fprintf(stderr, "[HTTP] 不支持的HTTP方法: %d\n", config->method);
             return HTTP_ERR_PARAM;  // 参数不合法
     }
 
     // 构建请求头链表（高效内存管理）
     if (config->headers) {
         struct curl_slist* headers = NULL;
         // 遍历头指针数组直到NULL终止符
         for (int i = 0; config->headers[i] != NULL; ++i) {
             headers = curl_slist_append(headers, config->headers[i]);  // 链表追加
         }
         // 更新全局头链表（原子替换）
         curl_easy_setopt(g_curl_handle, CURLOPT_HTTPHEADER, headers);
         curl_slist_free_all(g_header_list);  // 释放旧链表
         g_header_list = headers;  // 保存新链表
     }
 
     // 设置核心请求参数
     curl_easy_setopt(g_curl_handle, CURLOPT_URL, config->url);          // 目标URL
     curl_easy_setopt(g_curl_handle, CURLOPT_WRITEFUNCTION, callback);  // 响应回调
     curl_easy_setopt(g_curl_handle, CURLOPT_WRITEDATA, userdata);       // 用户上下文
 
     // 执行网络请求（阻塞操作）
     CURLcode res = curl_easy_perform(g_curl_handle);
     if (res != CURLE_OK) {
         log_curl_error(res, "curl_easy_perform");
         // 分类处理CURL错误码
         return (res == CURLE_OPERATION_TIMEDOUT) ? HTTP_ERR_TIMEOUT : HTTP_ERR_NETWORK;
     }
 
     return HTTP_OK;  // 请求成功
 }
 
 /**
 * @brief 设置全局请求超时时间
 * @param seconds 超时时间（秒）
 * 
 * 安全特性：
 * - 限制最大超时时间（防止不合理值）
 * - 线程安全配置更新
 * - 运行时参数即时生效
 */
void HTTP_SetTimeout(unsigned int seconds) {
    const unsigned int MAX_TIMEOUT = 1000000;  // 约11.57天的最大限制
    // 参数安全限制（防止整数溢出）
    g_timeout_sec = (seconds > MAX_TIMEOUT) ? MAX_TIMEOUT : seconds;
    
    // 动态更新已存在的CURL句柄配置
    if (g_curl_handle) {
        curl_easy_setopt(g_curl_handle, CURLOPT_TIMEOUT, g_timeout_sec);
    }
}
 
 unsigned int HTTP_GetCurrentTimeout(void) {
     return g_timeout_sec;
 }
 
 void HTTP_ClientCleanup() {
     //---------------------------------------
     // 清理CURL资源
     //---------------------------------------
     if (g_curl_handle) {
         curl_easy_cleanup(g_curl_handle);
         g_curl_handle = NULL;
     }
 
     //---------------------------------------
     // 清理持久化头链表
     //---------------------------------------
     if (g_header_list) {
         curl_slist_free_all(g_header_list);
         g_header_list = NULL;
     }
 
     //---------------------------------------
     // 清理证书路径内存
     //---------------------------------------
     if (g_ca_cert_path) {
         free(g_ca_cert_path);
         g_ca_cert_path = NULL;
     }
 
     //---------------------------------------
     // 清理CURL全局环境
     //---------------------------------------
     if (g_curl_global_initialized) {
         curl_global_cleanup();
         g_curl_global_initialized = false;
     }
 }
 
 //-----------------------------------------------------------------------------
 // 内部工具函数实现
 //-----------------------------------------------------------------------------
 
 /**
  * @brief 记录CURL错误日志
  */
 static void log_curl_error(CURLcode code, const char* context) {
     fprintf(stderr, "[CURL] 错误发生在: %s\n", context);
     fprintf(stderr, "[CURL] 错误代码: %d\n", code);
     fprintf(stderr, "[CURL] 错误描述: %s\n", curl_easy_strerror(code));
 }